package com.lexi.common.poi.word;

import com.lexi.common.poi.model.WordTableModel;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.*;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
public class WordChartsUtils {
private static final Pattern RANG_PATTERN=Pattern.compile("(:\\$[A-Z]+\\$)(\\d+)");

    /**
     * 刷新图表表格数据
     * @param chart
     * @param dataList
     * @param titleList
     * @param <T>
     * @return
     */
    @SneakyThrows
    public static<T> boolean refreshExcel(XWPFChart chart, List<T> dataList, List<WordTableModel> titleList) {
        boolean result = true;
        int startRow=1;
        @Cleanup
        XSSFWorkbook wb = new XSSFWorkbook();
        XSSFSheet sheet = wb.createSheet("Sheet1");
        XSSFRow curRow=getRow(sheet,0);
        //根据数据创建excel第一行标题行
        for (int i = 0; i < titleList.size(); i++) {
             WordTableModel model=titleList.get(i);
             XSSFCell cell=getCell(curRow,i);
             cell.setCellValue(model.getChnName());
        }
        //遍历数据行
        for (int i = 0; i < dataList.size(); i++) {
            T t = dataList.get(i);//数据行
            curRow=getRow(sheet,startRow+i);
            if(t==null){
                continue;
            }
            for(int j=0;i<titleList.size();j++){
                WordTableModel model=titleList.get(j);
                XSSFCell curCel=getCell(curRow,j);
                Object objValue=t.getClass().getDeclaredMethod(model.getAttName()).invoke(t);
                setCellValue(curCel,model,objValue);
            }

        }
        // 更新嵌入的workbook
        POIXMLDocumentPart xlsPart = chart.getRelations().get(0);
        @Cleanup
        OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream();
        wb.write(xlsOut);
        return result;
    }
    public static <T> void refreshChartCache(XWPFChart chart, List<T> dataList, List<WordTableModel> titleList) {
        CTChart ctChart=chart.getCTChart();
        CTPlotArea plotArea=ctChart.getPlotArea();
        if(!plotArea.getBarChartList().isEmpty()){
            //设置标题
            //setBarTitle(ctChart,"新标题");
            CTBarChart barChart=plotArea.getBarChartArray(0);
            List<WordTableModel> barTitles=titleList.stream().filter(o->o.getChartType()== ChartTypes.BAR).collect(Collectors.toList());
            List<CTBarSer> serList=barChart.getSerList();
            for(int i=0;i<serList.size();i++){
                CTBarSer ser=serList.get(i);
                refreshSer(dataList,barTitles.get(i),titleList.get(0),ser.getTx(),ser.getCat(),ser.getVal());
            }
        }
        if(!plotArea.getLineChartList().isEmpty()){
            //设置标题
            //setBarTitle(ctChart,"新标题");
            CTLineChart barChart=plotArea.getLineChartArray(0);
            List<WordTableModel> barTitles=titleList.stream().filter(o->o.getChartType()== ChartTypes.LINE).collect(Collectors.toList());
            List<CTLineSer> serList=barChart.getSerList();
            for(int i=0;i<serList.size();i++){
                CTLineSer ser=serList.get(i);
                refreshSer(dataList,barTitles.get(i),titleList.get(0),ser.getTx(),ser.getCat(),ser.getVal());
            }
        }
        if(!plotArea.getPieChartList().isEmpty()){
            //设置标题
            //setBarTitle(ctChart,"新标题");
            CTPieChart barChart=plotArea.getPieChartArray(0);
            List<WordTableModel> barTitles=titleList.stream().filter(o->o.getChartType()== ChartTypes.PIE).collect(Collectors.toList());
            List<CTPieSer> serList=barChart.getSerList();
            for(int i=0;i<serList.size();i++){
                CTPieSer ser=serList.get(i);
                refreshSer(dataList,barTitles.get(i),titleList.get(0),ser.getTx(),ser.getCat(),ser.getVal());
            }
        }
    }

    /**
     * 刷新SER
     * @param dataList
     * @param wordTableModel
     * @param firstCol
     * @param tx
     * @param cat
     * @param val
     * @param <T>
     */
    @SneakyThrows
    private static <T> void refreshSer(List<T> dataList, WordTableModel wordTableModel, WordTableModel firstCol, CTSerTx tx, CTAxDataSource cat, CTNumDataSource val) {
        CTStrData strData=cat.getStrRef().getStrCache();
        CTNumData numData=val.getNumRef().getNumCache();
        long oldSize=strData.getPtCount().getVal();
        strData.setPtArray((CTStrVal[]) null);
        numData.setPtArray((CTNumVal[]) null);
        long idx=0;
        for(int i=0;i<dataList.size();i++){
            T t=dataList.get(i);
            //Str
            CTStrVal strVal=strData.addNewPt();
            strVal.setIdx(idx);
            Object strObj=t.getClass().getDeclaredMethod(firstCol.getAttName()).invoke(t);
            strVal.setV(strVal.toString());
            //Val
            CTNumVal numVal=numData.addNewPt();
            numVal.setIdx(idx);
            Object numObj=t.getClass().getDeclaredMethod(wordTableModel.getAttName()).invoke(t);
            numVal.setV(numObj.toString());
            idx++;
        }
        strData.getPtCount().setVal(idx);
        numData.getPtCount().setVal(idx);
        //刷新横坐标区域
        cat.getStrRef().setF(getRowEnd(cat.getStrRef().getF(),oldSize,dataList.size()));
        //刷新数据区域
        val.getNumRef().setF(getRowEnd(cat.getNumRef().getF(),oldSize,dataList.size()));
    }

    /**
     * 获取数据区域
     * @param rangArea
     * @param oldSize
     * @param dataSize
     * @return
     */
    private static String getRowEnd(String rangArea, long oldSize, int dataSize) {
        Matcher matcher=RANG_PATTERN.matcher(rangArea);
        if(matcher.find()){
            long oldIndex=Long.parseLong(matcher.group(2));
            return rangArea.replaceAll("(:\\$[A-Z]+\\$)(\\d+)","$1"+Long.toString(oldIndex-oldSize+dataSize));
        }
        return rangArea;
    }

    /**
     * 获取内置表格数据，拿到第一行第一列格子数据
     * 有时候模板设计太复杂，对于图表不能精准定位，可以通过设置图表表格数据的第一行第一列格子数据来区分，这个数据不影响图表显示，所以用来区分每个图表
     */
    @SneakyThrows
    public static String getChartsKey(POIXMLDocumentPart poixmlDocumentPart) {
        String text = "";
        XWPFChart chart = (XWPFChart) poixmlDocumentPart;
        chart.getCTChart();
        POIXMLDocumentPart xlsPart = chart.getRelations().get(0);
        @Cleanup
        InputStream xlsin = xlsPart.getPackagePart().getInputStream();
        @Cleanup
        XSSFWorkbook workbook = new XSSFWorkbook(xlsin);
        // 获取第一个sheet
        XSSFSheet sheet = workbook.getSheetAt(0);
        // 第一行
        XSSFRow row = sheet.getRow(0);
        // 第一列
        XSSFCell cell = row.getCell(0);
        cell.setCellType(CellType.STRING);  // 设置一下格子类型为字符串，不然如果是数字或者时间的话，获取很麻烦
        text = cell.getStringCellValue();   // 获取格子内容
        log.info("chartsKey：" + text);
        return text.trim();
    }
    /**
     * 设置标题
     * @param ctChart
     * @param title
     */
    public static void setBarTitle(CTChart ctChart, String title) {
        CTTitle ctTitle = ctChart.getTitle();
        CTTx ctTx = ctTitle.getTx();
        if (null != ctTx) {
            CTTextBody ctTextBody = ctTx.getRich();
            List<CTTextParagraph> ctTextParagraphslist = ctTextBody.getPList();
            CTTextParagraph ctTextParagraph1 = ctTextParagraphslist.get(0);
            List<CTRegularTextRun> ctRegularTextRunslist = ctTextParagraph1.getRList();
            ctRegularTextRunslist.get(0).setT(title);  // 设置标题
        }
    }

    public static void setCellValue(XSSFCell cell,WordTableModel model,Object objValue){
        if(null==objValue){

        }else{
            cell.setCellValue(objValue.toString());
        }

    }

    public static XSSFCell getCell(XSSFRow row,int index){
        XSSFCell cell=row.getCell(index);
        if(null==cell){
            row.createCell(index);
        }
        return cell;
    }
    public static XSSFRow getRow(XSSFSheet sheet,int index){
        XSSFRow row=sheet.getRow(index);
        if(row==null){
            return sheet.createRow(index);
        }
        return row;
    }


}
